// -*- coding: utf-8 -*-

/**
 * @file hybrid_newton_reduction.h
 * @brief Implementation of a consistency for hybrid problems.
 */

#ifndef _HYBRID_NEWTON_REDUCTION_H
#define _HYBRID_NEWTON_REDUCTION_H

#include "vnode.h"

#include "elisa/elisa_interval_form.h"

#include "hybrid_config.h"
#include "hybrid_var.h"
#include "hybrid_model.h"
#include "hybrid_ode_solver.h"

NAMESPACE_ELISA

/**
 * @ingroup Hybrid
 * @class HybridNewtonReduction
 * @brief Projection operator implementing interval Newton method for hybrid problems
 */
class HybridNewtonReduction : public Reduction
{
public:
	/**
 	 * Constructor
 	 * @param c the constraint to reduce
 	 * @param v the var that the domain must be reduced
 	 * @param cons the factory for IntrevalForm
	 */
	HybridNewtonReduction(ContConstraint *cc, IntervalFormFactory *cons,
						  bool dump = false)
	    : m_constr(*cc),
		  m_odeSolver(*cc, dump),
		  m_initT(), m_endT()
	{
		Reduction::post(cc);
	}

	/**
 	 * Destructor
 	 */
	~HybridNewtonReduction()
	{
	}

	/// Base class's virtual methods
	//@{
	double priority() const
	{
		return 10.0;
	}

	bool narrow(bool, VNInterval&, VNIntVec&);
	bool newtonIt(VNInterval&, VNIntVec&);
	bool reductionAlgorithm();
	//@}


	string getReductionName() const
	{
		return "HybridNewton";
	}

	void print(std::ostream & os, std::string indent, VecConstraints *v) const
	{
		os << "HybridNewtonReduction [";
		printConstraints(os, "", v);
		os << "]";
	}

	//static bool dump;

private:
	//static const double MinH;
	//static const int    Ratio;
	static const double Factor;

#ifdef HYBRID_PROFILE
	// ダンプ出力。
	//static ofstream odeOut;
#endif

	// continuous constraint
	ContConstraint& m_constr;

	VNInterval	m_initT;
	VNInterval	m_endT;
	
	HybridOdeSolverImpl	m_odeSolver;
	//HybridOdeSolverImpl1	m_odeSolver;

	/// Copy protection
	HybridNewtonReduction& operator=(const HybridNewtonReduction&);
	HybridNewtonReduction(const HybridNewtonReduction&);
};


static VNIntVec ueEncls;
extern void ueReset();
extern bool ueEncl(const VNInterval& encl);


/**
 * @ingroup Hybrid
 * @class HybridNewtonReductionFactory
 * @brief Generation of a reduction for hybrid problems
 * @see HybridReduction
 */
class HybridNewtonReductionFactory : public ReductionFactory
{
public:
	/**
 	 * Constructor
 	 * @param cons the factory for the intervalForm
	 */
	HybridNewtonReductionFactory(IntervalFormFactory *iff, bool dump = false)
		: m_iff(iff), m_dump(dump)
	{
		//HybridNewtonReduction::dump = dump;
	}

	/**
 	 * Destructor
 	 * @post the factory for intervalForm has been deleted
 	 */
	~HybridNewtonReductionFactory()
	{
		delete m_iff;
	}

	/// @name Base class's virtual methods
	//@{
	void create(ModelRep *mo, SetReduction & s)
	{
		ConstraintHandler *ch = dynamic_cast<ConstraintHandler *>(mo);
		if (ch != 0) {
			ContConstraint *constraint = dynamic_cast<ContConstraint *>(ch->getConstraint());
			if (constraint != 0) {
				s.insert(new HybridNewtonReduction(constraint, m_iff, m_dump));
			}
		}
	}
//@}

private:
	// Generation of interval form used by box-consistency
	IntervalFormFactory *m_iff;
	bool m_dump;
};

END_NAMESPACE_ELISA

#endif //HYBRID_NEWTON_REDUCTION_H
